#ifndef CLOGGER_H
#define CLOGGER_H

/* 日志器用法说明
 * 仅需一行代码即可初始化日志器： CLogger::getInstance();
 *
 * 日志器配置说明
 * 启动后会从exe所在目录查找LogConfog.ini文件，如果不存在，按照默认配置生成文件LogConfog.ini
*/

#include <QObject>
#include <QMutex>
#include <QMutexLocker>
#include <QCoreApplication>
#include <QSettings>

const static QString LOG_DIR = QCoreApplication::applicationDirPath() + "/Log";
const static QString LOG_FMT = "%{if-debug}[DBUG%{endif}"
                                "%{if-info}\033[32m[INFO%{endif}"
                                "%{if-warning}\033[33m[WARN%{endif}"
                                "%{if-critical}\033[31m[ERRO%{endif}"
                                "%{if-fatal}\033[35m[FATL%{endif}]"
                                "%{time yyyyMMdd h:mm:ss.zzz}"
                                "%{function}:%{line} - %{message}\033[0m";


enum LogLevel{
    Debug = 0,
    Info,
    Warning,
    Error,
    Fatal,
};

class CAppender
{
public:
    CAppender(){}
    CAppender(LogLevel level):m_enmLevel(level){};
    virtual void setLevel(LogLevel level){m_enmLevel = level;}
    virtual void append(LogLevel level,const QString &msg) = 0;
protected:
    LogLevel m_enmLevel = LogLevel::Debug;
};

class CConsoleAppender : public CAppender
{
public:
    CConsoleAppender():CAppender(){}
    CConsoleAppender(LogLevel level):CAppender(level){}

    void append(LogLevel level,const QString &msg) override;
};

#include <QUdpSocket>

class CUdpAppender : public CAppender
{
public:
    CUdpAppender(LogLevel level,QString strRemoteIp = "127.0.0.1",quint16  nRemotePort = 9009);
    ~CUdpAppender();

    void setRemoteAddr(QString strIp,quint16 nPort);
    void append(LogLevel level,const QString &msg) override;
private:
    QUdpSocket *m_pUdp = nullptr;
    QString m_strRemoteIp;
    quint16  m_nRemotePort;
};


#include <QDir>
#include <QFileInfoList>
#include <QCollator>
#include <algorithm>

class CFileAppender : public CAppender
{
public:
    CFileAppender(LogLevel level, QString strFilePath = QCoreApplication::applicationDirPath() + "/Log");

    void setMaxSize(int nMB){m_nMaxSize = nMB * 1024 * 1024;}
    void setMaxCout(int nMaxCount){m_nMaxCount = nMaxCount;}
    void setLogPath(QString strPath);
    void append(LogLevel level,const QString &msg) override;
private:
    void redirectLog(QFile &file); //重定向日志输出的文件
    QFileInfoList entryInfoListFotCreate(QString strPath);
    bool isNeedRedirect()
    {
        //日志重定向的两个条件 满足其一即可  文件过大或日期已变更
        QFileInfo logInfo(m_fileLog);
        return logInfo.size() > m_nMaxSize || logInfo.fileTime(QFileDevice::FileBirthTime).date() != QDate::currentDate();
    }

private:
    QString m_strLogPath;
    QFile m_fileLog;
    int m_nMaxSize = 10 * 1024 * 1024;
    int m_nMaxCount = 10; // 最多保存日志个数
};

class CLogger : public QObject
{
    Q_OBJECT
public:
    explicit CLogger(QObject *parent = 0);
    static CLogger* getInstance();

#define SET_LEVEL(X) \
    void set##X##Level(LogLevel level) { \
        if(nullptr != m_p##X##Appender) \
            m_p##X##Appender->setLevel(level); \
    }

    SET_LEVEL(Console)
    SET_LEVEL(Udp)
    SET_LEVEL(File)
#undef SET_LEVEL

    void setRemoteAddr(QString strIp,quint16 nPort){
        if(nullptr != m_pUdpAppender)
            m_pUdpAppender->setRemoteAddr(strIp,nPort);
    }

    void setMaxSize(int nMB){
        if(nullptr != m_pFileAppender)
            m_pFileAppender->setMaxSize(nMB);
    }
    void setMaxCout(int nCount){
        if(nullptr != m_pFileAppender)
            m_pFileAppender->setMaxCout(nCount);
    }
    void setLogPath(QString strLogPath){
        if(nullptr != strLogPath){
            m_pFileAppender->setLogPath(strLogPath);
        }
    }

private:
    void init();

public slots:
    void slotAppendLog(LogLevel level,const QString &msg);
private:
    QSettings *m_pSettings = nullptr;

    CConsoleAppender *m_pConsoleAppender = nullptr;
    CUdpAppender *m_pUdpAppender = nullptr;
    CFileAppender *m_pFileAppender = nullptr;

    QList<CAppender *> m_listAppender;
signals:
    void sigLog(QString strLog); //供外部接入

};

#endif // CLOGGER_H
